package puzzle.slilin2.solver;

import puzzle.common.data.HatanException;
import puzzle.common.point.Pnt;
import puzzle.slilin2.data.CellType;
import puzzle.slilin2.data.LineCellState;
import puzzle.slilin2.data.NumberCellState;
import puzzle.slilin2.data.SlilinPntHelper;
import puzzle.slilin2.data.SlilinBoard;

/**
 * 数値セルに関する基本的なルール
 * 
 * @author tomoto
 */
class BasicNumberRule extends SlilinCellRule {

	@Override
	protected CellType appliedCellType() {
		return CellType.NUMBER;
	}

	@Override
	protected boolean skipOutside() {
		return true;
	}

	@Override
	protected boolean skipUnmodifiedCell() {
		return true;
	}

	public boolean apply(SlilinBoard b, Pnt p) throws HatanException {
		int n = b.getNumber(p);

		// 数値が入っていなければ何もしない
		if (n == NumberCellState.EMPTY) return false;

		// 周辺の線の状態数を数える
		LineCount lc = new LineCount(b, SlilinPntHelper.getLinePointsAroundNumber(b, p));

		// すべての線が決まっていれば何もしない
		if (lc.getUnfixedCellStates().size() == 0) return false;

		boolean isChanged = false;

		if (lc.getExistsCount() == n) {
			// 線の数が指定に達したので、空いている箇所を禁止にする
			isChanged = true;
			for (LineCellState s : lc.getUnfixedCellStates()) {
				s.setForbidden(true);
			}
		} else if (4 - lc.getForbiddenCount() == n) {
			// 禁止の数が指定に達したので、空いている箇所を線にする
			isChanged = true;
			for (LineCellState s : lc.getUnfixedCellStates()) {
				s.setExists(true);
			}
		} else if (lc.getExistsCount() > n || lc.getForbiddenCount() > 4 - n) {
			// 線の数がおかしい
			throw new HatanException();
		}

		return isChanged;
	}

}
